package co.fitstart.data.web.interceptor;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.springframework.web.util.WebUtils;

import com.demo2do.core.web.handler.CookieHandler;

import co.fitstart.data.Constant;
import co.fitstart.data.service.UserService;
import co.fitstart.entity.user.User;

/**
 * 
 * @author mohanlan
 *
 */
public class MobileDetectInterceptor extends HandlerInterceptorAdapter {
    
    private static final Logger logger = LoggerFactory.getLogger(MobileDetectInterceptor.class);
    
    private static final String SAVED_REQUEST = "MOBILE_SNIFFER_SAVED_REQUEST";
    
    private static final int MOBILE_COOKIE_EXPIRE = 7200;
    
    @Autowired
    private UserService userService;
    
    @Autowired
    private CookieHandler cookieHandler;
    
    /**
     * User mobile key stored in the cookie
     */
    private String mobileKey = Constant.MOBILE_KEY;
    
    /**
     * wechat openid key stored in the cookie
     */
    private String openidKey = Constant.OPENID_KEY;
    
    /**
     * URL where once no mobile found in the cookie, the browser should redirect to
     */
    private String loginUrl;
    
    
    /**
     * mobileKey The mobileKey to set
     * @param mobileKey
     */
    public void setMobileKey(String mobileKey) {
        this.mobileKey = mobileKey;
    }
    
    /**
     * @param openidKey The openidKey to set
     */
    public void setOpenidKey(String openidKey) {
        this.openidKey = openidKey;
    }
    
    /**
     * loginUrl The loginUrl to set
     * @param loginUrl
     */
    public void setLoginUrl(String loginUrl) {
        this.loginUrl = loginUrl;
    }
    
    /*
     * (non-Javadoc)
     * @see org.springframework.web.servlet.handler.HandlerInterceptorAdapter#preHandle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object)
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        
        if(handler instanceof HandlerMethod) {
            
            if(logger.isDebugEnabled()) {
                logger.debug("MobileSniffingInterceptor#preHandle() - To determine this request can be visited in addition to wechat client");
            }
            
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            
            MobileDetect mobileDetect = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), MobileDetect.class);
            if(mobileDetect == null ) {
                logger.info("MobileSniffingInterceptor#preHandle() - no mobile sniffing interceptor, return super prehandle");
                return super.preHandle(request, response, handler); 
            }
            
            logger.trace("MobileSniffingInterceptor#preHandle() - Get mobile cookie with mobile cookie key [{}].", mobileKey);
            Cookie mobileCookie = WebUtils.getCookie(request, mobileKey);
            
            logger.trace("MobileSniffingInterceptor#preHandle() - Get openid cookie with openid cookie key [{}].", openidKey);
            Cookie openidCookie = WebUtils.getCookie(request, openidKey);
            
            // if mobile cookie not exit but openidCookie exit
            if(mobileCookie == null && openidCookie != null) {
                // try to load user by user openid and save user mobile cookie
                String openid = openidCookie.getValue();
                
                User user = userService.getUserByOpenId(openid);
                
                logger.trace("MobileSniffingInterceptor#preHandle() - Openid cookie exit, try to save user's mobile into cookie which get by openid cookie exit mobile");
                
                if(user != null && StringUtils.isNoneBlank(user.getMobile())) {
                    
                    logger.trace("MobileSniffingInterceptor#preHandle() - user not exit and user has mobile, save user mobile into cookie");
                    
                    mobileCookie = new Cookie(mobileKey, user.getMobile());
                    mobileCookie.setMaxAge(MOBILE_COOKIE_EXPIRE);
                    cookieHandler.addCookie(response, mobileCookie);
                    
                    String originalUri = com.demo2do.core.web.utils.WebUtils.getRealRequestURI(request);
                    String queryString = request.getQueryString();
                    
                    String originalUrl = StringUtils.isBlank(queryString) ? originalUri : (originalUri + "?" + queryString);
                    String resolvedAuthUrl = originalUrl.startsWith("http") ? originalUrl : (com.demo2do.core.web.utils.WebUtils.getRealServerPath(request) + originalUrl);
                    logger.trace("MobileSniffingInterceptor#preHandle() - The resolved URL is [{}].", resolvedAuthUrl);
                    response.sendRedirect(resolvedAuthUrl);
                    return false;
                }
            }
            
            if(!mobileDetect.autoLogin() ){
                logger.trace("MobileSniffingInterceptor#preHandle() - This controller does not need to login, just return to super prehandler");
                return super.preHandle(request, response, handler);
            }
            
            if(mobileDetect.autoLogin() && mobileCookie == null) {
                
                saveOriginalRequest(request);  // Save original request URL
                
                String resolvedTargetUrl = loginUrl.startsWith("http") ?
                        loginUrl : (com.demo2do.core.web.utils.WebUtils.getRealServerPath(request) + loginUrl);
                logger.trace("MobileSniffingInterceptor#preHandle() - The resolved login URL is [{}].", resolvedTargetUrl);
                
                response.sendRedirect(resolvedTargetUrl);
                return false;
            }
        }
        
        return super.preHandle(request, response, handler);
    }
    
    /**
     * Save original request in HTTP session for further reference
     * 
     * @param request
     */
    private void saveOriginalRequest(HttpServletRequest request) {
        
        // Construct original URL from request URI and query string
        String originalUri = com.demo2do.core.web.utils.WebUtils.getRealRequestURI(request);
        String queryString = request.getQueryString();
        
        String originalUrl = StringUtils.isBlank(queryString) ? originalUri : (originalUri + "?" + queryString);
        
        // Save the original URL in the session currently
        HttpSession httpSession = request.getSession();
        httpSession.setAttribute(SAVED_REQUEST, originalUrl);
    }
}
